Passed
Push — master ( 761c2b...002ff1 )
by Emmanuel
01:45
created

$.fn.formJS   B

Complexity

Conditions 1
Paths 128

Size

Total Lines 289
Code Lines 157

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 3 Features 3
Metric Value
cc 1
eloc 157
c 5
b 3
f 3
nc 128
nop 1
dl 0
loc 289
rs 7

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/*
2
 * Copyright (c) 2018.  JAGFx
3
 * @author: SMITH Emmanuel
4
 * @version: 2.0.0
5
 */
6
7
(function ( $ ) {
8
	$.fn.formJS = function ( options ) {
9
		var obj = this;
10
11
		var settings = $.extend( true, {
12
			alerts:      {
13
				unexpected: {
14
					title:   'Error',
15
					message: 'Unexpected error occurred'
16
				},
17
				failSend:   {
18
					title:   'Error',
19
					message: 'Unable to send data'
20
				}
21
			},
22
			keys:        {
23
				success: 'success',
24
				info:    'info',
25
				warning: 'warning',
26
				error:   'error'
27
			},
28
			icons:       {
29
				loading: '<span>&#8987;</span>',
30
				success: '<span>&#10003;</span>',
31
				info:    '<span>&#128712;</span>',
32
				warning: '<span>&#65111;</span>',
33
				error:   '<span>&#10799;</span>'
34
			},
35
			form:        {
36
				ajaxSettings:     {
37
					contentType: false
38
				},
39
				alertContainer:   '.formJS',
40
				btnSubmit:        '.btn[type="submit"]',
41
				enableWriteAlert: true
42
			},
43
			redirection: {
44
				message: 'Automatic redirection in a second',
45
				delay:   1100
46
			},
47
			callback:    function ( currentAlert ) {
0 ignored issues
show
Unused Code introduced by
The parameter currentAlert is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
48
			}
49
		}, options );
50
51
		return obj.each( function () {
52
			var $this        = $( this );
53
			var action       = $this.attr( "action" );
54
			var method       = $this.attr( "method" );
55
			var btnSubmit    = $this.find( settings.form.btnSubmit );
56
			var currentAlert = $.extend( settings.alerts.unexpected, { type: 'error' } );
57
			var ajaxPending  = false;
58
			var ajaxSettings;
59
			var formdata;
60
			var data;
61
			
62
			/**
63
			 * Sending data method
64
			 * @param e
65
			 */
66
			$this.sendData = function ( e ) {
67
				e.preventDefault();
68
				
69
				// --------------- Check if an ajax request is in precessing
70
				if ( ajaxPending === false )
71
					ajaxPending = true;
72
				else return;
73
				
74
				try {
75
					// --------------- Check if a submit button is found
76
					if ( btnSubmit.length === 0 )
77
						throw 'Unable to find submit button';
78
					
79
					// --------------- Check if form method is found
80
					if ( method == "" || method === null )
81
						throw 'Undefined method of form';
82
					
83
					// --------------- Add loader and disabled submit button
84
					btnSubmit
85
						.append( $( settings.icons.loading ).addClass( 'formJS-loading' ) )
86
						.attr( 'disabled' );
87
					
88
					btnSubmit.addClass( 'disabled' );
89
					
90
					// --------------- Prepare ajax setting
91
					formdata     = (window.FormData) ? new FormData( $this[ 0 ] ) : null;
92
					data         = (formdata !== null) ? formdata : $this.serialize();
93
					ajaxSettings = $.extend( settings.form.ajaxSettings, {
94
						url:         action,
95
						type:        method,
96
						data:        data,
97
						processData: false
98
					} );
99
					
100
					$this.trigger( 'formjs:submit', [ ajaxSettings, ajaxPending ] );
101
					
102
					// --------------- Send ajax request
103
					$.ajax( ajaxSettings )
104
						.done( function ( feedback ) {
105
							try {
106
								// --------------- If no feedback found, write unexpected alert
107
								if ( feedback.length === 0 )
108
									throw 'No data found on response';
109
								
110
								var feedbackData = $.parseJSON( feedback );
111
								var notif        = '';
112
								
113
								$this.trigger( 'formjs:ajax-success', [ feedback ] );
114
								
115
								// --------------- Check feedback structure
116
								$this.checkFeedbackStructure( feedbackData );
117
								
118
								// --------------- If url field is in feedback,  prepare to redirect to it
119
								if ( feedbackData.type === settings.keys.success && feedbackData.hasOwnProperty( 'url' ) ) {
120
									notif = ' - ' + settings.redirection.message;
121
									
122
									setTimeout( function () {
123
										window.location.replace( feedbackData.url );
124
									}, settings.redirection.delay );
125
								}
126
								
127
								// --------------- Make alert object with feedback
128
								currentAlert.type    = feedbackData.type;
129
								currentAlert.title   = feedbackData.data.title;
130
								currentAlert.message = feedbackData.data.message + notif;
131
								
132
							} catch ( error ) {
133
								$this.logError( 'AjaxSuccessCallback', error, feedback );
134
							}
135
						} )
136
						.fail( function ( error ) {
137
							$this.logError( 'AjaxFailCallback', error );
138
						} )
139
						.always( function () {
140
							// --------------- Call after all ajax request
141
							$this.writeAlert();
142
						} );
143
					
144
				} catch ( error ) {
145
					// --------------- Call if an error thrown before sending ajax request
146
					$this.logError( 'PreSubmit', error );
147
					$this.writeAlert();
148
				}
149
			};
150
			
151
			/**
152
			 * Process to sending data from the current form object
153
			 */
154
			$this.submit( $this.sendData );
155
			
156
			/**
157
			 * Process to sending data from on other way from the formJS plugin
158
			 */
159
			$this.on( 'formjs:send-form', $this.sendData );
160
161
			/**
162
			 * Check the structure of feedback response
163
			 * @param inputData
164
			 */
165
			$this.checkFeedbackStructure = function ( inputData ) {
166
				/**
167
				 * feedbackStructure = {
168
						type: '',
169
						url:  '',
170
						data: {
171
							title:   '',
172
							message: ''
173
						}
174
					};
175
				 */
176
177
				if ( !inputData.hasOwnProperty( 'type' ) )
178
					throw 'Invalid feedback structure: "type" missing';
179
180
				if ( !inputData.hasOwnProperty( 'data' ) )
181
					throw 'Invalid feedback structure: "data" missing';
182
183
				if ( !inputData.data.hasOwnProperty( 'title' ) )
184
					throw 'Invalid feedback structure: "data.title" missing';
185
186
				if ( !inputData.data.hasOwnProperty( 'message' ) )
187
					throw 'Invalid feedback structure: "data.message" missing';
188
189
				if ( Object.keys( settings.keys ).indexOf( inputData.type ) === -1 )
190
					throw 'Invalid feedback structure: "type" wrong. Accepted values: ' + Object.keys( settings.keys ).toString();
191
			};
192
			
193
			/**
194
			 * Log and trigger error event when error are occurred during the submit processing
195
			 * @param place Where the error are occurred
196
			 * @param message Error message
197
			 * @param data Additional data about this error
198
			 */
199
			$this.logError = function ( place, message, data ) {
200
				var mess = message.message || message;
201
				
202
				console.error( '[FormJS][' + place + '] ' + mess );
203
				
204
				$this.trigger( 'formjs:error', [ place, mess, data ] );
205
			};
206
207
			/**
208
			 * Create DOM alert
209
			 */
210
			$this.writeAlert = function () {
211
				$this.trigger( 'formjs:write-alert', [ currentAlert ] );
212
				
213
				if ( settings.form.enableWriteAlert === true ) {
214
					// --------------- Create alert DOM element
215
					var alert = $( '<div class="alert formjs-' + settings.keys[ currentAlert.type ] + '" role="alert" />' )
216
						.html( '<div class="ico">\n\
217
								' + settings.icons[ currentAlert.type ] + '\n\
218
							</div>\n\
219
							<div class="info">\n\
220
								<h4>' + currentAlert.title + '</h4>\n\
221
								<p>' + currentAlert.message + '</p>\n\
222
							</div>' )
223
						.hide()
224
						.fadeIn( 300 );
225
					
226
					// --------------- Add alert DOM element to the container
227
					$( settings.form.alertContainer )
228
						.empty()
229
						.html( alert );
230
				}
231
232
				// --------------- Scroll top
233
				$( 'html, body' ).animate( {
234
					scrollTop: $( settings.form.alertContainer ).offset().top - 55
235
				}, 300 );
236
237
				// --------------- Enable formJS process and enabled submit button
238
				var btnSubmit = $( settings.form.btnSubmit );
239
				if ( btnSubmit !== undefined && btnSubmit.length ) {
240
					btnSubmit
241
						.find( '.formJS-loading' )
242
						.remove();
243
244
					btnSubmit.removeClass( 'disabled' );
245
246
					ajaxPending = false;
247
				}
248
249
				// --------------- Print alert into developper console
250
				if ( currentAlert.type === 'success' || currentAlert.type === 'info' )
251
					console.log( currentAlert.title + " - " + currentAlert.message );
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
252
253
				else if ( currentAlert.type === 'error' )
254
					console.error( currentAlert.title + " - " + currentAlert.message );
255
256
				else if ( currentAlert.type === 'warning' )
257
					console.warn( currentAlert.title + " - " + currentAlert.message );
258
259
				else
260
					console.log( currentAlert.title + " - " + currentAlert.message );
261
262
				settings.callback( currentAlert );
263
			};
264
265
			/**
266
			 * Create the container if it not found
267
			 */
268
			$this.init = function () {
269
				var container = $this.find( settings.form.alertContainer );
270
271
				if ( container.length === 0 ) {
272
					var $el        = $( '<div/>' );
273
					var props      = settings.form.alertContainer.split( '.' ),
274
						newelement = $el,
275
						id         = '',
276
						className  = '';
277
					$.each( props, function ( i, val ) {
278
						if ( val.indexOf( '#' ) >= 0 ) {
279
							id += val.replace( /^#/, '' );
280
						} else {
281
							className += val + ' ';
282
						}
283
					} );
284
285
					if ( id.length ) newelement.attr( 'id', id );
286
					if ( className.length ) newelement.attr( 'class', className.trim() );
287
288
					$this.prepend( newelement );
289
				}
290
			};
291
292
			$this.init();
293
			
294
			return $this;
295
		} );
296
	};
297
298
})( jQuery );
299